#include "movegenerator.h"

void MoveGenerator::clearMoveList() {
    moveList.clear();
}

// Init rank, file and diagonal 6-bit patterns
void MoveGenerator::initMasks() {
    size_t rank, file;
    // SQUARE is used to translate [file][rank] to [square],
    for (rank = 0 ; rank < 8; rank++)
    {
          for (file = 0 ; file < 8; file++)
          {
                 SQUARE[file][rank] = rank * 8 + file; // ranging 0..63
          }
    }

    for (int i=0; i < 64; i++)
    {
          RANKMASK[i] = 0x0;
          FILEMASK[i] = 0x0;
          DIAGA8H1MASK[i] = 0x0;
          DIAGA1H8MASK[i] = 0x0;
          FILEMAGICBOARD[i] = 0x0;
          DIAGA8H1MAGIC[i] = 0x0;
          DIAGA1H8MAGIC[i] = 0x0;
    }

    for (int file = 0; file < 8; file++)
    {
      for (int rank = 0; rank < 8; rank++)
      {
          RANKMASK[SQUARE[file][rank]]  = Bitutils::Bit(SQUARE[1][rank]) | Bitutils::Bit(SQUARE[2][rank]) |
                                          Bitutils::Bit(SQUARE[3][rank]) | Bitutils::Bit(SQUARE[4][rank]) |
                                          Bitutils::Bit(SQUARE[5][rank]) | Bitutils::Bit(SQUARE[6][rank]) ;

          FILEMASK[SQUARE[file][rank]]  = Bitutils::Bit(SQUARE[file][1]) | Bitutils::Bit(SQUARE[file][2]) |
                                          Bitutils::Bit(SQUARE[file][3]) | Bitutils::Bit(SQUARE[file][4]) |
                                          Bitutils::Bit(SQUARE[file][5]) | Bitutils::Bit(SQUARE[file][6]) ;

          // File MAGIC Numbers
          FILEMAGICBOARD[SQUARE[file][rank]] = FILE_MAGIC_ARRAY[file];
          // Diagonal MAGIC Numbers
          DIAGA8H1MAGIC[SQUARE[file][rank]] = _DIAGA8H1MAGICS[file+rank];
          DIAGA1H8MAGIC[SQUARE[file][rank]] = _DIAGA1H8MAGICS[file-rank+7];

            // Diagonal Masks
            DIAGA8H1MASK[SQUARE[file][rank]] = 0x0;
            if (file+rank < 8)  // lower half, diagonals 0 to 7
            {
                 for (int i=0 ; i < file+rank-1 ; i++)
                 {
                     DIAGA8H1MASK[SQUARE[file][rank]] |= Bitutils::Bit(SQUARE[i+1][file+rank-(i+1)]); // i -> i+1
                 }
            }
            else  // upper half, diagonals 8 to 15
            {
                 for (int i=0 ; i < 15 - (file+rank) ; i++)
                 {
                        DIAGA8H1MASK[SQUARE[file][rank]] |= Bitutils::Bit(SQUARE[file+rank+i-7][7-i]);
                 }
            }

            DIAGA1H8MASK[SQUARE[file][rank]] = 0x0;
            if (file-rank > -1)  // lower half, diagonals 0 to 7
            {
               for (int i=0 ; i < 8 - (file-rank) ; i++)
                 {
                   DIAGA1H8MASK[SQUARE[file][rank]] |= Bitutils::Bit(SQUARE[(file-rank) + i][i]);
                 }
            }
            else
            {
               for (int i=0 ; i < 8 + (file-rank) ; i++)
                 {
                   DIAGA1H8MASK[SQUARE[file][rank]] |= Bitutils::Bit(SQUARE[i][i - (file-rank)]);
                 }
            }
      }
    }
    qDebug() << "Move generator masks initialised";
}

// get piece id from board square i
size_t MoveGenerator::getCapturedPiece(size_t i) {
    if (WHITE_TO_MOVE == board_.sideToMove) {
        if (Bitutils::checkBit(board_.bP, i)) return BLACK_PAWN;
        if (Bitutils::checkBit(board_.bN, i)) return BLACK_KNIGHT;
        if (Bitutils::checkBit(board_.bB, i)) return BLACK_BISHOP;
        if (Bitutils::checkBit(board_.bR, i)) return BLACK_ROOK;
        if (Bitutils::checkBit(board_.bQ, i)) return BLACK_QUEEN;
        if (Bitutils::checkBit(board_.bK, i)) return BLACK_KING;
    }

    if (BLACK_TO_MOVE == board_.sideToMove) {
        if (Bitutils::checkBit(board_.wP, i)) return WHITE_PAWN;
        if (Bitutils::checkBit(board_.wN, i)) return WHITE_KNIGHT;
        if (Bitutils::checkBit(board_.wB, i)) return WHITE_BISHOP;
        if (Bitutils::checkBit(board_.wR, i)) return WHITE_ROOK;
        if (Bitutils::checkBit(board_.wQ, i)) return WHITE_QUEEN;
        if (Bitutils::checkBit(board_.wK, i)) return WHITE_KING;
    }

    // no captured piece found
    return EMPTY;
}

// pseudo-legal move generator
// - missing castling, en-passant and promotion to be tested
// sliding pieces only rooks
void MoveGenerator::generateMoves() {
    // clear move list
    moveList.clear();

    // move variables
    Move move;
        move.castling = EMPTY;
    U64 havePieces;
    U64 haveSquares;
    size_t rank_pattern;
    size_t file_pattern;

    // target squares
    U64 wTargetSquares = ~board_.wPieces; // available squares for white to move
    U64 bTargetSquares = ~board_.bPieces; // available squares for black to move

    if (WHITE_TO_MOVE == board_.sideToMove) // white to move
    {
        // TODO add castling technique
        qDebug() << "Generate white moves";
        move.piece = WHITE_KING;
        havePieces = board_.wK; // dummy bitboard to loop through all pieces
        if (!board_.wK) qDebug() << "Error no white king found";
        while (havePieces) {
            //qDebug() << "Found a white king";
            move.from = Bitutils::firstOne(havePieces);
            haveSquares = KING_ATTACKS[move.from] & wTargetSquares; // do not attack white pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                // only go to squares that are not attacked by black pieces
                if (isFieldAttacked(move.to, board_.sideToMove)) {
                    // remove bit from haveSquares
                    haveSquares ^= Bitutils::Bit(move.to);
                    continue;
                }
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "wK: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }

            // white 0-0 Castling:
            if (board_.wCanCastle00)
                // if free space for king to castle AND not king not attacked AND fields in between are not attacked
                // AND there is a white rook in the corner (who has not moved, which is controlled by flags)
                if ((!(board_.occupiedSquares & (Bitutils::Bit(F1)|Bitutils::Bit(G1))))
                        && (!isFieldAttacked(E1, board_.sideToMove)
                        && (!isFieldAttacked(F1, board_.sideToMove))
                        && (!isFieldAttacked(G1, board_.sideToMove))
                        && (Bitutils::checkBit(board_.wR, H1)))) {
                    // store castle move WITHOUT rooks!!! these are then actually moved in movemaker when castling occurs
                    move.to = G1;
                    move.captured = EMPTY;
                    move.castling = WHITE_00_CASTLING_MOVE;
                    // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                    Move addMove(move);
                    qDebug() << "wK: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    moveList.push_back(addMove); // add this move to moveList
                }
            // white 0-0-0 Castling:
            if (board_.wCanCastle000)
                // if free space for king to castle AND not king not attacked AND fields in between are not attacked
                // AND there is a white rook in the corner (who has not moved, which is controlled by flags)
                if ((!(board_.occupiedSquares & (Bitutils::Bit(B1)|Bitutils::Bit(C1)|Bitutils::Bit(D1))))
                        && (!isFieldAttacked(E1, board_.sideToMove)
                        && (!isFieldAttacked(D1, board_.sideToMove))
                        && (!isFieldAttacked(C1, board_.sideToMove))
                        && (Bitutils::checkBit(board_.wR, A1)))) {
                    // store castle move WITHOUT rooks!!! these are then actually moved in movemaker when castling occurs
                    move.to = C1;
                    move.captured = EMPTY;
                    move.castling = WHITE_000_CASTLING_MOVE;
                    // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                    Move addMove(move);
                    qDebug() << "wK: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    moveList.push_back(addMove); // add this move to moveList
                }
            move.castling = EMPTY;
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = WHITE_KNIGHT;
        havePieces = board_.wN; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a white knight";
            move.from = Bitutils::firstOne(havePieces);
            haveSquares = KNIGHT_ATTACKS[move.from] & wTargetSquares; // do not attack white pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "wN: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = WHITE_ROOK;
        havePieces = board_.wR; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a white rook";
            move.from = Bitutils::firstOne(havePieces);
            rank_pattern = (board_.occupiedSquares & RANKMASK[move.from]) >> RANKSHIFT[move.from];
            file_pattern = ((board_.occupiedSquares & FILEMASK[move.from]) * FILEMAGICBOARD[move.from]) >> 57; // 57 also magic :-)
            haveSquares = (RANK_ATTACKS[move.from][rank_pattern] | FILE_ATTACKS[move.from][file_pattern])
                            & wTargetSquares; // do not attack white pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                if (board_.bN == 4611686018427388160) {
                    int holdit = 0;
                }
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "wR: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = WHITE_BISHOP;
        havePieces = board_.wB; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a white bishop";
            move.from = Bitutils::firstOne(havePieces);

            haveSquares =
            (DIAGA8H1_ATTACKS[move.from][((board_.occupiedSquares & DIAGA8H1MASK[move.from])
                                            * DIAGA8H1MAGIC[move.from]) >> 57] |
             DIAGA1H8_ATTACKS[move.from][((board_.occupiedSquares & DIAGA1H8MASK[move.from])
                                            * DIAGA1H8MAGIC[move.from]) >> 57])

                    & wTargetSquares; // do not attack white pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "wB: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = WHITE_QUEEN;
        havePieces = board_.wQ; // dummy bitboard to loop through all pieces
        while (havePieces) {  
            qDebug() << "Found a white queen";
            move.from = Bitutils::firstOne(havePieces);
            rank_pattern = (board_.occupiedSquares & RANKMASK[move.from]) >> RANKSHIFT[move.from];
            file_pattern = ((board_.occupiedSquares & FILEMASK[move.from]) * FILEMAGICBOARD[move.from]) >> 57; // 57 also magic :-)          
            haveSquares = // BISHOP moves
                    ((DIAGA8H1_ATTACKS[move.from][((board_.occupiedSquares & DIAGA8H1MASK[move.from])
                                                    * DIAGA8H1MAGIC[move.from]) >> 57] |
                     DIAGA1H8_ATTACKS[move.from][((board_.occupiedSquares & DIAGA1H8MASK[move.from])
                                                    * DIAGA1H8MAGIC[move.from]) >> 57])
                    | // or ROOK moves
                    (RANK_ATTACKS[move.from][rank_pattern] | FILE_ATTACKS[move.from][file_pattern]))
                        // on any non-white square
                    & wTargetSquares;

            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "wQ: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = WHITE_PAWN;
        havePieces = board_.wP; // dummy bitboard to loop through all pieces
        while (havePieces) {
            move.from = Bitutils::firstOne(havePieces);
            haveSquares = WHITE_PAWN_MOVES[move.from] & (~board_.occupiedSquares);
            haveSquares |= (~board_.occupiedSquares) & (~board_.occupiedSquares << 8)
                            & WHITE_PAWN_DOUBLE_MOVES[move.from];
            haveSquares |= WHITE_PAWN_ATTACKS[move.from] & board_.bPieces;      // pawn attacks a piece

            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);

                if (move.to >= 56)  // move on 8th rank -> pawn must promote
                {
                    move.promotion = WHITE_QUEEN; Move addMoveQ(move); moveList.push_back(addMoveQ);
                    move.promotion = WHITE_ROOK; Move addMoveR(move); moveList.push_back(addMoveR);
                    move.promotion = WHITE_BISHOP; Move addMoveB(move); moveList.push_back(addMoveB);
                    move.promotion = WHITE_KNIGHT; Move addMoveN(move); moveList.push_back(addMoveN);
                    qDebug() << "wP: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    qDebug() << "wP: PROMOTION FOUND";
                }
                else {
                    move.promotion = EMPTY; // let it be empty again... for next moves calculations
                    // normal move is finished - copy and add to list! (takes some time... maybe c-style here?)
                    Move addMove(move);
                    qDebug() << "wP: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    moveList.push_back(addMove); // add this move to moveList
                }
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }

            // special case! En-passant
            // en passant square is set, so there was a starting double-pawn-move before,
            // then we can capture on this empty field in between
            if (WHITE_PAWN_ATTACKS[move.from] & Bitutils::Bit(board_.enPassantSquare)
                    && ISIN(board_.enPassantSquare,40,47))
            {
                             //move.setProm(WHITE_PAWN);
                             move.to = board_.enPassantSquare;
                             //move.captured = getCapturedPiece(move.to);
                             move.promotion = EMPTY;
                             // en-passant move is finished - copy and add to list! (takes some time... maybe c-style here?)
                             Move addMove(move);
                             qDebug() << "wP: "
                                         + QString(SQUARENAME[move.from]) + " - "
                                         + QString(SQUARENAME[move.to]);
                             moveList.push_back(addMove); // add this move to moveList
            }

            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
            move.promotion = EMPTY; // let it be empty again... for next moves calculations
        }


    }
    if (BLACK_TO_MOVE == board_.sideToMove) { // black to move
        // TODO add castling technique
        qDebug() << "Generate black moves";
        move.piece = BLACK_KING;
        havePieces = board_.bK; // dummy bitboard to loop through all pieces
        if (!board_.bK) qDebug() << "Error no black king found";
        while (havePieces) {
            //qDebug() << "Found a black king";
            move.from = Bitutils::firstOne(havePieces);
            haveSquares = KING_ATTACKS[move.from] & bTargetSquares; // do not attack black pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                // only go to squares that are not attacked by white pieces
                if (isFieldAttacked(move.to, board_.sideToMove)) {
                    // remove bit from haveSquares
                    haveSquares ^= Bitutils::Bit(move.to);
                    continue;
                }
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "bK: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // black 0-0 Castling:
            if (board_.bCanCastle00)
                // if free space for king to castle AND not king not attacked AND fields in between are not attacked
                // AND there is a white rook in the corner (who has not moved, which is controlled by flags)
                if ((!(board_.occupiedSquares & (Bitutils::Bit(F8)|Bitutils::Bit(G8))))
                        && (!isFieldAttacked(E8, board_.sideToMove)
                        && (!isFieldAttacked(F8, board_.sideToMove))
                        && (!isFieldAttacked(G8, board_.sideToMove))
                        && (Bitutils::checkBit(board_.bR, H8)))) {
                    // store castle move WITHOUT rooks!!! these are then actually moved in movemaker when castling occurs
                    move.to = G8;
                    move.captured = EMPTY;
                    move.castling = BLACK_00_CASTLING_MOVE;
                    // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                    Move addMove(move);
                    qDebug() << "wK: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    moveList.push_back(addMove); // add this move to moveList
                }
            // black 0-0-0 Castling:
            if (board_.bCanCastle000)
                // if free space for king to castle AND not king not attacked AND fields in between are not attacked
                // AND there is a white rook in the corner (who has not moved, which is controlled by flags)
                if ((!(board_.occupiedSquares & (Bitutils::Bit(B8)|Bitutils::Bit(C8)|Bitutils::Bit(D8))))
                        && (!isFieldAttacked(E8, board_.sideToMove)
                        && (!isFieldAttacked(D8, board_.sideToMove))
                        && (!isFieldAttacked(C8, board_.sideToMove))
                        && (Bitutils::checkBit(board_.bR, A8)))) {
                    // store castle move WITHOUT rooks!!! these are then actually moved in movemaker when castling occurs
                    move.to = C8;
                    move.captured = EMPTY;
                    move.castling = BLACK_000_CASTLING_MOVE;
                    // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                    Move addMove(move);
                    qDebug() << "wK: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    moveList.push_back(addMove); // add this move to moveList
                }

            move.castling = EMPTY;
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = BLACK_KNIGHT;
        havePieces = board_.bN; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a black knight";
            move.from = Bitutils::firstOne(havePieces);
            haveSquares = KNIGHT_ATTACKS[move.from] & bTargetSquares; // do not attack white pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "bN: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = BLACK_ROOK;
        havePieces = board_.bR; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a black rook";
            move.from = Bitutils::firstOne(havePieces);
            rank_pattern = (board_.occupiedSquares & RANKMASK[move.from]) >> RANKSHIFT[move.from];
            file_pattern = ((board_.occupiedSquares & FILEMASK[move.from]) * FILEMAGICBOARD[move.from]) >> 57; // 57 also magic :-)
            haveSquares = (RANK_ATTACKS[move.from][rank_pattern] | FILE_ATTACKS[move.from][file_pattern])
                            & bTargetSquares; // do not attack black pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "bR: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = BLACK_BISHOP;
        havePieces = board_.bB; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a black bishop";
            move.from = Bitutils::firstOne(havePieces);

            haveSquares =
            (DIAGA8H1_ATTACKS[move.from][((board_.occupiedSquares & DIAGA8H1MASK[move.from])
                                            * DIAGA8H1MAGIC[move.from]) >> 57] |
             DIAGA1H8_ATTACKS[move.from][((board_.occupiedSquares & DIAGA1H8MASK[move.from])
                                            * DIAGA1H8MAGIC[move.from]) >> 57])

                    & bTargetSquares; // do not attack black pieces
            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "bB: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        move.piece = BLACK_QUEEN;
        havePieces = board_.bQ; // dummy bitboard to loop through all pieces
        while (havePieces) {
            qDebug() << "Found a black queen";
            move.from = Bitutils::firstOne(havePieces);
            rank_pattern = (board_.occupiedSquares & RANKMASK[move.from]) >> RANKSHIFT[move.from];
            file_pattern = ((board_.occupiedSquares & FILEMASK[move.from]) * FILEMAGICBOARD[move.from]) >> 57; // 57 also magic :-)
            haveSquares = // BISHOP moves
                    ((DIAGA8H1_ATTACKS[move.from][((board_.occupiedSquares & DIAGA8H1MASK[move.from])
                                                    * DIAGA8H1MAGIC[move.from]) >> 57] |
                     DIAGA1H8_ATTACKS[move.from][((board_.occupiedSquares & DIAGA1H8MASK[move.from])
                                                    * DIAGA1H8MAGIC[move.from]) >> 57])
                    | // or ROOK moves
                    (RANK_ATTACKS[move.from][rank_pattern] | FILE_ATTACKS[move.from][file_pattern]))
                        // on any non-white square
                    & bTargetSquares;

            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);
                // move is finished - copy and add to list! (takes some time... maybe c-style here?)
                Move addMove(move);
                qDebug() << "bQ: "
                            + QString(SQUARENAME[move.from]) + " - "
                            + QString(SQUARENAME[move.to]);
                moveList.push_back(addMove); // add this move to moveList
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }
            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
        }

        //TODO test promotion
        move.piece = BLACK_PAWN;
        havePieces = board_.bP; // dummy bitboard to loop through all pieces
        while (havePieces) {
            move.from = Bitutils::firstOne(havePieces);
            haveSquares = BLACK_PAWN_MOVES[move.from] & (~board_.occupiedSquares);
            haveSquares |= (~board_.occupiedSquares) & (~board_.occupiedSquares << 8)
                            & BLACK_PAWN_DOUBLE_MOVES[move.from];
            haveSquares |= BLACK_PAWN_ATTACKS[move.from] & board_.wPieces;      // pawn attacks a piece

            while (haveSquares) {
                move.to = Bitutils::firstOne(haveSquares);
                move.captured = getCapturedPiece(move.to);

                if (move.to <= 7)  // move on 1th rank -> pawn must promote
                {
                    move.promotion = BLACK_QUEEN; Move addMoveQ(move); moveList.push_back(addMoveQ);
                    move.promotion = BLACK_ROOK; Move addMoveR(move); moveList.push_back(addMoveR);
                    move.promotion = BLACK_BISHOP; Move addMoveB(move); moveList.push_back(addMoveB);
                    move.promotion = BLACK_KNIGHT; Move addMoveN(move); moveList.push_back(addMoveN);

                    qDebug() << "bP: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    qDebug() << "bP: PROMOTION FOUND";
                }
                else {
                    move.promotion = EMPTY;
                    // normal move is finished - copy and add to list! (takes some time... maybe c-style here?)
                    Move addMove(move);
                    qDebug() << "bP: "
                                + QString(SQUARENAME[move.from]) + " - "
                                + QString(SQUARENAME[move.to]);
                    moveList.push_back(addMove); // add this move to moveList
                }
                // remove bit from haveSquares
                haveSquares ^= Bitutils::Bit(move.to);
            }

            // special case! En-passant
            // en passant square is set, so there was a starting double-pawn-move before,
            // then we can capture on this empty field in between
            if ((BLACK_PAWN_ATTACKS[move.from] & Bitutils::Bit(board_.enPassantSquare))
                    && ISIN(board_.enPassantSquare,16,23))
            {
                             //move.setProm(BLACK_PAWN);
                             move.to = board_.enPassantSquare;
                             //move.captured = getCapturedPiece(move.to);
                             move.promotion = EMPTY;
                             // en-passant move is finished - copy and add to list! (takes some time... maybe c-style here?)
                             Move addMove(move);
                             qDebug() << "bP: "
                                         + QString(SQUARENAME[move.from]) + " - "
                                         + QString(SQUARENAME[move.to]);
                             moveList.push_back(addMove); // add this move to moveList
            }

            // remove bit from havePieces
            havePieces ^= Bitutils::Bit(move.from);
            move.promotion = EMPTY; // let it be empty again... for next moves calculations
        }
    }

    qDebug() << "Move generator run completed";
}

// *** separate file
// initialize attack patterns
void MoveGenerator::initAttacks() {
    for (int i = 0; i < 64; i++) {
        KNIGHT_ATTACKS[i] = 0x0ULL;
        KING_ATTACKS[i] = 0x0ULL;
        WHITE_PAWN_ATTACKS[i] = 0x0ULL;
        WHITE_PAWN_MOVES[i] = 0x0ULL;
        WHITE_PAWN_DOUBLE_MOVES[i] = 0x0ULL;
        BLACK_PAWN_ATTACKS[i] = 0x0ULL;
        BLACK_PAWN_MOVES[i] = 0x0ULL;
        BLACK_PAWN_DOUBLE_MOVES[i] = 0x0ULL;
        for (size_t pattern = 0; pattern < 64; pattern++)
        {
            RANK_ATTACKS[i][pattern] = 0x0ULL;
            FILE_ATTACKS[i][pattern] = 0x0ULL;
            DIAGA8H1_ATTACKS[i][pattern] = 0x0ULL;
            DIAGA1H8_ATTACKS[i][pattern] = 0x0ULL;
        }
    }


    // WHITE_PAWN_ATTACKS
    for (int i = 8; i < 56; i++)  // never have white pawn on 1st rank and last rank does not attack
    {
        if (i % 8 == 0) { // 1st file
            WHITE_PAWN_ATTACKS[i] |= Bitutils::Bit(i+9);
        }
        else if ((i+1) % 8 == 0) { // 8th file - next file would be 1st! with mod 8 == 0
                WHITE_PAWN_ATTACKS[i] |= Bitutils::Bit(i+7);
             }
             else { // inner file pawn has left & right attack
                WHITE_PAWN_ATTACKS[i] |= Bitutils::Bit(i+7);
                WHITE_PAWN_ATTACKS[i] |= Bitutils::Bit(i+9);
             }
    }

    // WHITE_PAWN_MOVES -- including DOUBLE_MOVES
    for (int i = 8; i < 56; i++)  // never have white pawn on 1st rank and last rank that can move
    {
        WHITE_PAWN_MOVES[i] |= Bitutils::Bit(i+8); // +8  = advance one rank, stay in same file
        if ((i >= 8) && (i <= 15)) {
            WHITE_PAWN_DOUBLE_MOVES[i] |= Bitutils::Bit(i+16); // on 2nd rank, double move is possible
        }
    }

    // BLACK_PAWN_ATTACKS
    for (int i = 8; i < 56; i++)  // never have BLACK pawn on 1st rank and last rank does not attack
    {
        if (i % 8 == 0) { // 1st file
            BLACK_PAWN_ATTACKS[i] |= Bitutils::Bit(i-7);
        }
        else if ((i+1) % 8 == 0) { // 8th file - next file would be 1st! with mod 8 == 0
                BLACK_PAWN_ATTACKS[i] |= Bitutils::Bit(i-9);
             }
             else { // inner file pawn has left & right attack
                BLACK_PAWN_ATTACKS[i] |= Bitutils::Bit(i-7);
                BLACK_PAWN_ATTACKS[i] |= Bitutils::Bit(i-9);
             }
    }

    // BLACK_PAWN_MOVES -- including DOUBLE_MOVES
    for (int i = 8; i < 56; i++)  // never have BLACK pawn on 1st rank and last rank that can move
    {
        BLACK_PAWN_MOVES[i] |= Bitutils::Bit(i-8); // +8  = advance one rank, stay in same file
        if ((i >= 48) && (i <= 55)) {
            BLACK_PAWN_DOUBLE_MOVES[i] |= Bitutils::Bit(i-16); // on 2nd rank, double move is possible
        }
    }

    // KING_ATTACKS;
    for (int i = 0; i < 64; i++) // all squares
    {
        // check whether within board limits and distance between two squares is 0 or 1 ranks and files
        if (ISIN(i+1, 0, 64) && ISIN(RANKDIFF(i,i+1),0,1) && ISIN(FILEDIFF(i,i+1),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i+1);
        }
        if (ISIN(i-1, 0, 64) && ISIN(RANKDIFF(i,i-1),0,1) && ISIN(FILEDIFF(i,i-1),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i-1);
        }
        if (ISIN(i+8, 0, 64) && ISIN(RANKDIFF(i,i+8),0,1) && ISIN(FILEDIFF(i,i+8),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i+8);
        }
        if (ISIN(i-8, 0, 64) && ISIN(RANKDIFF(i,i-8),0,1) && ISIN(FILEDIFF(i,i-8),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i-8);
        }
        if (ISIN(i+9, 0, 64) && ISIN(RANKDIFF(i,i+9),0,1) && ISIN(FILEDIFF(i,i+9),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i+9);
        }
        if (ISIN(i-9, 0, 64) && ISIN(RANKDIFF(i,i-9),0,1) && ISIN(FILEDIFF(i,i-9),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i-9);
        }
        if (ISIN(i+7, 0, 64) && ISIN(RANKDIFF(i,i+7),0,1) && ISIN(FILEDIFF(i,i+7),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i+7);
        }
        if (ISIN(i-7, 0, 64) && ISIN(RANKDIFF(i,i-7),0,1) && ISIN(FILEDIFF(i,i-7),0,1)) {
            KING_ATTACKS[i] |= Bitutils::Bit(i-7);
        }


    }

    // KNIGHT_ATTACKS;
    for (int i = 0; i < 64; i++) // all squares
    {
        // check whether within board limits and distance between two squares is 1 or 2 ranks and files
        if (ISIN(i+6, 0, 64) && ISIN(RANKDIFF(i,i+6),1,2) && ISIN(FILEDIFF(i,i+6),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i+6);
        }
        if (ISIN(i+10, 0, 64) && ISIN(RANKDIFF(i,i+10),1,2) && ISIN(FILEDIFF(i,i+10),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i+10);
        }
        if (ISIN(i+15, 0, 64) && ISIN(RANKDIFF(i,i+15),1,2) && ISIN(FILEDIFF(i,i+15),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i+15);
        }
        if (ISIN(i+17, 0, 64) && ISIN(RANKDIFF(i,i+17),1,2) && ISIN(FILEDIFF(i,i+17),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i+17);
        }
        if (ISIN(i-6, 0, 64) && ISIN(RANKDIFF(i,i-6),1,2) && ISIN(FILEDIFF(i,i-6),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i-6);
        }
        if (ISIN(i-10, 0, 64) && ISIN(RANKDIFF(i,i-10),1,2) && ISIN(FILEDIFF(i,i-10),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i-10);
        }
        if (ISIN(i-15, 0, 64) && ISIN(RANKDIFF(i,i-15),1,2) && ISIN(FILEDIFF(i,i-15),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i-15);
        }
        if (ISIN(i-17, 0, 64) && ISIN(RANKDIFF(i,i-17),1,2) && ISIN(FILEDIFF(i,i-17),1,2)) {
            KNIGHT_ATTACKS[i] |= Bitutils::Bit(i-17);
        }
    }

    // RANK_ATTACKS - calculated ... 64  x64(6bit pattern for all piece positions) then saved and looked up!
    // FILE_ATTACKS - using same rank_pattern on rotated and shifted attack_pattern
    // DIAG_ATTACKS - .....
    // BUG_FREE ROOK_SLIDING now
    for (int i = 0; i < 64; i++) { // all squares on first rank
        // bit (code) of 6bits starting with 0 (no pieces)
        for (unsigned char rank_pattern = 0x0U; rank_pattern < 64; rank_pattern++) { // use an 8-bit value here (only 6 used)
            unsigned char attack_pattern = 0x0U;
            U64 attack_pattern_64 = 0x0ULL;
            size_t rank =(i/8);
            size_t file =(i%8);

            // build 6bit attack_pattern for current position i in rank
            int pos = i%8;
            // go max steps to left side
            while (pos > 1) {
                // being rank_pattern index one below of attack_patterns' for same square
                Bitutils::setBit8(attack_pattern, pos-1);
                if (Bitutils::checkBit8(rank_pattern, pos-2)) break; // end search when piece is blocking direction
                pos--;
            }
            pos = i%8;
            // go max steps to right side
            while (pos < 6) {
                // being rank_pattern index one below of attack_patterns' for same square
                Bitutils::setBit8(attack_pattern, pos+1);
                if (Bitutils::checkBit8(rank_pattern, pos)) break; // end search when piece is blocking direction
                pos++;
            }

            // extend attack_pattern to 8bit
            // first and last file are attacked only if file next to them is (attacked & empty)
            if ((!Bitutils::checkBit8(rank_pattern, 0)) && (Bitutils::checkBit8(attack_pattern, 1))
                    && /* not being at the left edge*/ (i%8 != 0) || (i%8 == 1)) { // next to edge always attacks
               Bitutils::setBit8(attack_pattern, 0);
            }
            if ((!Bitutils::checkBit8(rank_pattern, 5)) && (Bitutils::checkBit8(attack_pattern, 6))
                    && /* not being at the right edge*/ (i%8 != 7) || (i%8 == 6)) { // next to edge always attacks
               Bitutils::setBit8(attack_pattern, 7);
            }


            //if ((i == C8) && (rank_pattern == 33)) { qDebug() << (attack_pattern << (8*(rank-1))) ;}
            // shift attack_pattern to corresponding rank of piece square
            attack_pattern_64 |= (U64(attack_pattern) << (8*rank)); // do conversion to whole bitboard (filled with zeros)
            // add U64 attack_pattern indexed by 6bit rank_pattern

            RANK_ATTACKS[i][rank_pattern] |= attack_pattern_64;

            // FILE attack bits
                   //        LSB         MSB                               . . . . . m . . MSB
                   //        m n o p q r s t                    =>         . . . . . n . .
                   //                                                      . . . . . o . .
                   //                                                      . . . . . p . .
                   //                                                      . . . . . q . .
                   //                                                      . . . . . r . .
                   //                                                      . . . . . s . .
                   //                                                 LSB  . . . . . t . .
            // TODO Look for inverse multiplication scheme
            size_t rot_i = Bitutils::rotate90Clockwise(i);
            size_t rot_file =(rot_i%8);
            U64 file_attack_inversed = 0x0ULL;
            for (size_t b = 0; b < 8; b++) {
                if (Bitutils::checkBit8(attack_pattern, b)) {
                    Bitutils::setBit(file_attack_inversed, 63 - (7-rot_file) - 8*b);
                }

            }
            FILE_ATTACKS[rot_i][rank_pattern] |= file_attack_inversed;


        } // end rank_pattern
    } // end board loop

    // DIAG_ATTACKS  - running through i (0..63) all fields
                                 // -- running through all attack patterns (0..63)
    // new board and rank_pattern loops for diagonals - cause using "generic" ROOK_ATTACKS
    for (int i = 0; i < 64; i++) { // all squares on first rank
        // bit (code) of 6bits starting with 0 (no pieces)
        for (unsigned char rank_pattern = 0x0U; rank_pattern < 64; rank_pattern++) { // use an 8-bit value here (only 6 used)

            // top left a8 down to h1;
            // \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

            // loop through all bits in attack_pattern - (file+rank determines current diagonal)
            // MAJOR TRICK forget high attack-bits on small diagonals!!!
            for (size_t attack_pattern_bit = 0; attack_pattern_bit < 8; attack_pattern_bit++) {
                size_t rank =(i/8); // square loop
                size_t file =(i%8);

                size_t cFile;
                size_t cRank; // current file,rank in inner loop

                // check if attack_bit is set - yeah but do it with GENERIC RANK PATTERN FROM ROOKS!!!
                // which has 8 bits on ground rank

                if (Bitutils::checkBit(RANK_ATTACKS[Bitutils::diagA8H1RankTool(i)][rank_pattern],attack_pattern_bit)) {

                    if ((file+rank) < 8) // left-bottom half including max diagonal
                    {
                        cFile = attack_pattern_bit;
                        cRank = (file+rank) - cFile;
                    }
                    else { // top right half diagonals
                        cRank = 7 - attack_pattern_bit;
                        cFile = (file+rank) - cRank;
                    }
                    if (ISIN(cFile,0,7) && ISIN(cRank,0,7))
                        DIAGA8H1_ATTACKS[i][rank_pattern] |= Bitutils::Bit(SQUARE[cFile][cRank]);
                }
            }
            // buttom left a1 up to h8;
            // //////////////////////////////////////////////////////////////////////////////////
            // loop through all bits in attack_pattern
            // MAJOR TRICK forget high attack-bits on small diagonals!!!
            for (size_t attack_pattern_bit = 0; attack_pattern_bit < 8; attack_pattern_bit++) {
                int rank =(i/8); // square loop // INFO:. These must be int's cause we run a test with neg outcome
                int file =(i%8);

                size_t cFile;
                size_t cRank; // current file,rank in inner loop
                // check if attack_bit is set - yeah but do it with GENERIC RANK PATTERN FROM ROOKS!!!
                // which has 8 bits on ground rank

                if (Bitutils::checkBit(RANK_ATTACKS[Bitutils::diagA1H8RankTool(i)][rank_pattern],attack_pattern_bit)) {
                    if ((file-rank) < 0) // top left half diagonals // BUGGY :-(
                    {
                        cFile = attack_pattern_bit;
                        cRank = cFile-(file-rank);
                    }
                    else { // buttom right half diagonals // BUG-FREE
                        cRank = attack_pattern_bit;
                        cFile = (file-rank) + cRank;
                    }
                    if (ISIN(cFile,0,7) && ISIN(cRank,0,7)) {
                        DIAGA1H8_ATTACKS[i][rank_pattern] |= Bitutils::Bit(SQUARE[cFile][cRank]);
                    }
                }
            }

        } // end rank_pattern
    } // end board loop

    qDebug() << "Move generator attack patterns finished";
}

// check whether the pos i on board is attacked
// needs to be evaluated mainly for the king!
// also handles sideToMove check
bool MoveGenerator::isFieldAttacked(size_t i, bool sideToMove)
{

    // white's move
    if (WHITE_TO_MOVE == sideToMove) {
       // sliding pieces (queens and rooks) - horizontal and vertical
       if (MoveGenerator::FILE_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::FILEMASK[i]) * MoveGenerator::FILEMAGICBOARD[i]) >> 57]
               & (board_.bQ | board_.bR))
           return true;
       if (MoveGenerator::RANK_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::RANKMASK[i]) >> RANKSHIFT[i])]
               & (board_.bQ | board_.bR))
           return true;

       //  sliding pieces (queens and bishops) - diagonal
       if ((MoveGenerator::DIAGA8H1_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::DIAGA8H1MASK[i])
                                       * MoveGenerator::DIAGA8H1MAGIC[i]) >> 57] |
            MoveGenerator::DIAGA1H8_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::DIAGA1H8MASK[i])
                                       * MoveGenerator::DIAGA1H8MAGIC[i]) >> 57])
               & (board_.bQ | board_.bB))
           return true;

       // knights
       if (MoveGenerator::KNIGHT_ATTACKS[i] & board_.bN)
           return true;

       // pawns
       if (MoveGenerator::WHITE_PAWN_ATTACKS[i] & board_.bP)
           return true;

       // king
       if (MoveGenerator::KING_ATTACKS[i] & board_.bK)
           return true;
    }

    // black's move
    if (BLACK_TO_MOVE == sideToMove) {
        // sliding pieces (queens and rooks) - horizontal and vertical
        if (MoveGenerator::FILE_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::FILEMASK[i]) * MoveGenerator::FILEMAGICBOARD[i]) >> 57]
                & (board_.wQ | board_.wR))
            return true;
        if (MoveGenerator::RANK_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::RANKMASK[i]) >> RANKSHIFT[i])]
                & (board_.wQ | board_.wR))
            return true;

        //  sliding pieces (queens and bishops) - diagonal
        if ((MoveGenerator::DIAGA8H1_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::DIAGA8H1MASK[i])
                                        * MoveGenerator::DIAGA8H1MAGIC[i]) >> 57] |
             MoveGenerator::DIAGA1H8_ATTACKS[i][((board_.occupiedSquares & MoveGenerator::DIAGA1H8MASK[i])
                                        * MoveGenerator::DIAGA1H8MAGIC[i]) >> 57])
                & (board_.wQ | board_.wB))
            return true;

        // knights
        if (MoveGenerator::KNIGHT_ATTACKS[i] & board_.wN)
            return true;

        // pawns
        if (MoveGenerator::BLACK_PAWN_ATTACKS[i] & board_.wP)
            return true;

        // king
        if (MoveGenerator::KING_ATTACKS[i] & board_.wK)
            return true;
    }

    // default is non-attacked
    return false;
}

bool MoveGenerator::isOwnKingAttacked()
{
       // check to see if we are leaving our king in check
       if (BLACK_TO_MOVE == board_.sideToMove)
       {
           return isFieldAttacked(Bitutils::firstOne(board_.bK), BLACK_TO_MOVE);
       }
       else
       {
           return isFieldAttacked(Bitutils::firstOne(board_.wK), WHITE_TO_MOVE);
       }
}

bool MoveGenerator::isOtherKingAttacked()
{
       // check to see if we are leaving the other king in check
       if (BLACK_TO_MOVE == board_.sideToMove)
       {
           return isFieldAttacked(Bitutils::firstOne(board_.wK), WHITE_TO_MOVE);
       }
       else
       {
           return isFieldAttacked(Bitutils::firstOne(board_.bK), BLACK_TO_MOVE);
       }
}


// precalculated attack patterns
U64 MoveGenerator::WHITE_PAWN_ATTACKS[64];
U64 MoveGenerator::WHITE_PAWN_MOVES[64];
U64 MoveGenerator::WHITE_PAWN_DOUBLE_MOVES[64];
U64 MoveGenerator::BLACK_PAWN_ATTACKS[64];
U64 MoveGenerator::BLACK_PAWN_MOVES[64];
U64 MoveGenerator::BLACK_PAWN_DOUBLE_MOVES[64];
U64 MoveGenerator::KNIGHT_ATTACKS[64];
U64 MoveGenerator::KING_ATTACKS[64];

unsigned char MoveGenerator::SQUARE[8][8];
U64 MoveGenerator::RANKMASK[64];
U64 MoveGenerator::FILEMASK[64];
U64 MoveGenerator::FILEMAGICBOARD[64];
U64 MoveGenerator::DIAGA8H1MASK[64];
U64 MoveGenerator::DIAGA8H1MAGIC[64];
U64 MoveGenerator::DIAGA1H8MASK[64];
U64 MoveGenerator::DIAGA1H8MAGIC[64];

U64 MoveGenerator::RANK_ATTACKS[64][64];      // 32KB
U64 MoveGenerator::FILE_ATTACKS[64][64];      // 32KB
U64 MoveGenerator::DIAGA8H1_ATTACKS[64][64];  // 32KB
U64 MoveGenerator::DIAGA1H8_ATTACKS[64][64];  // 32KB
